'use strict';

const path = require('path');
const fs = require('fs');

/** 默认参数配置 */
const DEFAULT_CONFIG = {
	isRename: true,
	isVersion: true,
	isMainJs: true,
	isStyleCss: true,
	isCocos2dJs: false,
	isSplashPng: false,

	isSrcSettingsJs: true,
	isSrcAssets: false,

	isZip: false,
};

/** 配置文件路径 */
const CONFIG_PATH = path.join(__dirname, './config.json');

function getConfig() {
	const configJson = JSON.parse(JSON.stringify(DEFAULT_CONFIG));
	if (fs.existsSync(CONFIG_PATH)) {
		const localConfig = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8'));
		for (const key in configJson) {
			if (localConfig[key] !== undefined) {
				configJson[key] = localConfig[key];
			}
		}
	}
	return configJson;
}

function setConfig(data) {
	const configJson = JSON.parse(JSON.stringify(DEFAULT_CONFIG));
	for (const key in configJson) {
		if (data[key] !== undefined) {
			configJson[key] = data[key];
		}
	}
	fs.writeFileSync(CONFIG_PATH, JSON.stringify(configJson, null, 2));
}

/** 格式化时间 */
function formatDate(date, fmt = 'yyyy-MM-dd hh:mm:ss') {
	const o = {
		'M+': date.getMonth() + 1, // 月
		'd+': date.getDate(), // 日
		'h+': date.getHours(), // 时
		'm+': date.getMinutes(), // 分
		's+': date.getSeconds(), // 秒
		'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
		S: date.getMilliseconds(), // 毫秒
	};
	if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
	for (const k in o) if (new RegExp('(' + k + ')').test(fmt)) fmt = fmt.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length));
	return fmt;
}

/** 插入字符串 */
function insertStr(searchStr, oldStr, newStr) {
	const index = oldStr.indexOf(searchStr);
	if (index == -1) {
		return oldStr;
	}

	return oldStr.slice(0, index) + newStr + oldStr.slice(index);
}

// const isVersion = true; // 是否更新版本号
// const isMainJs = true; // 是否合并 main.js
// const isStyleCss = true; // 是否合并 style-mobile.css

// const isSrcSettingsJs = true; // 是否合并 src/settings.js
// const isSrcAssets = true; // 是否合并 src/ 内其他文件

// const isZip = true; // 是否压缩

/** 在构建结束 之前 触发，此时除了计算文件 MD5、生成 settings.js、原生平台的加密脚本以外，大部分构建操作都已执行完毕。我们通常会在这个事件中对已经构建好的文件做进一步处理。 */
function onBeforeBuildFinish(options, callback) {
	// index.html 文件
	const htmlJsPath = path.join(options.dest, 'index.html'); // 获取发布目录下的 index.html 所在路径
	let htmlScript = fs.readFileSync(htmlJsPath, 'utf8'); // 读取构建好的 index.html
	if (getConfig().isMainJs || getConfig().isStyleCss || getConfig().isSrcSettingsJs) {
		htmlScript = htmlScript.replace(/<\!--(?:(?!-->)[\s\S])*-->/g, ''); // 删除所有注释
	}
	if (getConfig().isMainJs) {
		let oldString = '<script src="main.js" charset="utf-8"></script>';
		while (htmlScript.indexOf(oldString) !== -1) {
			htmlScript = htmlScript.replace(oldString, ''); // 删除 main.js 标签
		}
		oldString = '<script src="main.js" charset="utf-8"> </script>';
		while (htmlScript.indexOf(oldString) !== -1) {
			htmlScript = htmlScript.replace(oldString, ''); // 删除 main.js 标签
		}
	}
	if (getConfig().isStyleCss) {
		let oldString = '<link rel="stylesheet" type="text/css" href="style-mobile.css"/>';
		while (htmlScript.indexOf(oldString) !== -1) {
			htmlScript = htmlScript.replace(oldString, ''); // 删除 style-mobile.css 标签
		}
		oldString = '<link rel="stylesheet" type="text/css" href="style-mobile.css" />';
		while (htmlScript.indexOf(oldString) !== -1) {
			htmlScript = htmlScript.replace(oldString, ''); // 删除 style-mobile.css 标签
		}
	}
	if (getConfig().isSrcSettingsJs) {
		let oldString = '<script src="src/settings.js" charset="utf-8"></script>';
		while (htmlScript.indexOf(oldString) !== -1) {
			htmlScript = htmlScript.replace(oldString, ''); // 删除 src/settings.js 标签
		}
		oldString = '<script src="src/settings.js" charset="utf-8"> </script>';
		while (htmlScript.indexOf(oldString) !== -1) {
			htmlScript = htmlScript.replace(oldString, ''); // 删除 src/settings.js 标签
		}
	}

	// main.js 文件
	const mainJsPath = path.join(options.dest, 'main.js'); // 获取发布目录下的 main.js 所在路径
	let mainScript = fs.readFileSync(mainJsPath, 'utf8'); // 读取构建好的 main.js
	if (getConfig().isVersion) {
		const dateString = formatDate(new Date());
		Editor.success('Building window.GameVersionId = ' + dateString); // 你可以在控制台输出点什么
		mainScript += '\n' + `window.GameVersionId = "${dateString}";`; // 添加一点脚本到
		fs.writeFileSync(mainJsPath, mainScript); // 保存 main.js
	}
	if (getConfig().isMainJs) {
		Editor.success(`合并 main.js 文件`);
		htmlScript = insertStr('<script type="text/javascript">', htmlScript, `\n<script type="text/javascript">\n${mainScript}\n</script>\n`); // 合并 main.js
		// htmlScript = insertStr('(function () {', htmlScript, `\n${mainScript}\n`); // 合并 main.js
		fs.rmSync(mainJsPath, { force: true });
	}

	// style-mobile.css、style-desktop.css 文件
	const styleMobileCssPath = path.join(options.dest, 'style-mobile.css'); // 获取发布目录下的 style-mobile.css 所在路径
	const styleDesktopCssPath = path.join(options.dest, 'style-desktop.css'); // 获取发布目录下的 style-desktop.css 所在路径
	const styleScript = fs.readFileSync(styleMobileCssPath, 'utf8'); // 读取构建好的 style-mobile.css
	if (getConfig().isStyleCss) {
		Editor.success(`合并 style-mobile.css、style-desktop.css 文件`);
		htmlScript = insertStr('<title>', htmlScript, `\n<style type="text/css">\n${styleScript}\n</style>\n`); // 合并 main.js
		fs.rmSync(styleMobileCssPath, { force: true });
		fs.rmSync(styleDesktopCssPath, { force: true });
	}

	if (getConfig().isStyleCss || getConfig().isMainJs) {
		fs.writeFileSync(htmlJsPath, htmlScript); // 保存 index.html
	}

	// cocos2d-js-min.js 文件
	const cocos2dJsPath = path.join(options.dest, 'cocos2d-js-min.js'); // 获取发布目录下的 cocos2d-js-min.js 所在路径
	if (getConfig().isCocos2dJs) {
		fs.rmSync(cocos2dJsPath, { force: true });
	}

	// splash.png 文件
	const splashPngPath = path.join(options.dest, 'splash.png'); // 获取发布目录下的 splash.png 所在路径
	if (getConfig().isSplashPng) {
		fs.rmSync(splashPngPath, { force: true });
	}

	callback?.();
}

const AdmZip = require('adm-zip');
// 排除一些不需要压缩的分包
const exclude = ['internal', 'main', 'resources'];

/** 构建完全结束时触发。 */
function onBuildFinish(options, callback) {
	const srcPath = path.join(options.dest, 'src'); // 获取发布目录下的 src/ 所在路径

	const paths = [];
	let readdirpaths = (path) => {
		let files = fs.readdirSync(path);
		files.forEach(function (item) {
			let data = fs.statSync(path + '/' + item);
			if (data.isFile()) {
				if (getConfig().isSrcSettingsJs || getConfig().isSrcAssets) {
					console.log('文件名', item);
				}
				paths.push(path + '/' + item);
			} else {
				console.log('文件夹名', item);
				readdirpaths(path + '/' + item);
			}
		});
	};
	readdirpaths(srcPath);

	const htmlJsPath = path.join(options.dest, 'index.html'); // 获取发布目录下的 index.html 所在路径
	let htmlScript = fs.readFileSync(htmlJsPath, 'utf8'); // 读取构建好的 index.html

	if (getConfig().isSrcSettingsJs || getConfig().isSrcAssets) {
		Editor.success(`合并 src/ 内文件`);
		Editor.log(paths);
	}

	let settingsJsPath = undefined;
	for (let index = 0; index < paths.length; index++) {
		let itemScript = fs.readFileSync(paths[index], 'utf8'); // 读取构建好的 src/ 内所有文件
		if (paths[index].includes('settings')) {
			settingsJsPath = paths[index];

			if (getConfig().isSrcAssets) {
				itemScript = itemScript.replace(/jsList:\[[^\]]*\]/, 'jsList:[]'); // 清空 jsList，避免重复加载
			}
			if (getConfig().isZip) {
				const bundleVersMatch = itemScript.match(/bundleVers:(\{[^}]+\})/);
				const bundleVersStr = bundleVersMatch[1];
				const bundleVers = JSON.parse(bundleVersStr.replace(/([a-zA-Z_]\w*):/g, '"$1":')); // 修改为对象格式
				const assetsPath = path.join(options.dest, 'assets'); // 获取发布目录下的 src/ 所在路径

				Object.entries(bundleVers).forEach(([key, value]) => {
					if (exclude.includes(key)) return;

					const folderPath = path.join(assetsPath, key);
					if (fs.existsSync(folderPath) && fs.lstatSync(folderPath).isDirectory()) {
						Editor.log(`找到文件夹: ${key}, 开始压缩内容...`);

						// 创建 zip
						const zip = new AdmZip();
						const subItems = fs.readdirSync(folderPath);

						subItems.forEach((item) => {
							const fullPath = path.join(folderPath, item);
							if (fs.lstatSync(fullPath).isDirectory()) {
								zip.addLocalFolder(fullPath, item);
							}
						});

						// 生成 zip
						const zipName = `${key}.${value}.zip`;
						const outputPath = path.join(folderPath, zipName);
						zip.writeZip(outputPath);
						Editor.success(`压缩完成: ${outputPath}`);

						// 删除原目录（保留 zip）
						subItems.forEach((item) => {
							const targetPath = path.join(folderPath, item);
							if (fs.lstatSync(targetPath).isDirectory()) {
								fs.rmSync(targetPath, { recursive: true, force: true });
								Editor.log(`已删除目录: ${targetPath}`);
							}
						});
						Editor.log(`已删除原目录内容: ${folderPath}`);
					} else {
						Editor.warn(`未找到文件夹: ${key}`);
					}
				});

				Editor.success('全部压缩完成 ✅');
			}
			if (getConfig().isSrcSettingsJs) {
				Editor.success(`合并第${index + 1}个文件`, paths[index]);
				htmlScript = insertStr('<script type="text/javascript">', htmlScript, `\n<script type="text/javascript">\n${itemScript}\n</script>\n`); // 合并
			}
		} else {
			if (getConfig().isSrcAssets) {
				Editor.success(`合并第${index + 1}个文件`, paths[index]);
				htmlScript = insertStr('<script type="text/javascript">', htmlScript, `\n<script type="text/javascript">\n${itemScript}\n</script>\n`); // 合并
			}
		}
	}

	if (getConfig().isSrcSettingsJs && getConfig().isSrcAssets) {
		fs.rmdirSync(srcPath, { recursive: true }); // 删除整个 src 文件夹
	} else if (getConfig().isSrcSettingsJs && settingsJsPath) {
		fs.rmSync(settingsJsPath, { force: true }); // 删除 src/settings.xxxxx.js 文件
	} else if (getConfig().isSrcAssets) {
		const srcAssetsPath = srcPath + '/' + 'assets';
		fs.rmdirSync(srcAssetsPath, { recursive: true }); // 删除整个 src/assets 文件夹
	}

	if (getConfig().isSrcSettingsJs || getConfig().isSrcAssets) {
		Editor.success('合并后index.html', htmlScript);
		fs.writeFileSync(htmlJsPath, htmlScript); // 保存 index.html
	}

	// 强制删除非空目录
	if (getConfig().isRename) {
		fs.rmdirSync(path.join(options.buildPath, options.projectName), { recursive: true });
		fs.renameSync(options.dest, path.join(options.buildPath, options.projectName));
	}

	callback?.();
}

module.exports = {
	load() {
		Editor.Builder.on('before-change-files', onBeforeBuildFinish);
		Editor.Builder.on('build-finished', onBuildFinish);
	},

	unload() {
		Editor.Builder.removeListener('before-change-files', onBeforeBuildFinish);
		Editor.Builder.removeListener('build-finished', onBuildFinish);
	},

	// register your ipc messages here
	messages: {
		open() {
			Editor.Panel.open('ccc-build-complete');
		},

		saveData() {
			const info = Editor.Ipc.sendToPanel('ccc-build-complete', 'ccc-build-complete:saveData');

			// isVersion = info.isVersion;
			// isMainJs = info.isMainJs;
			// isStyleCss = info.isStyleCss;
			// isSrcSettingsJs = info.isSrcSettingsJs;
			// isSrcAssets = info.isSrcAssets;
			// isZip = info.isZip;

			Editor.success('保存成功!');
			Editor.Panel.close('ccc-build-complete');
		},
	},
};
